﻿/*
通用表单验证方法
Validform version 5.3.2
By sean during April 7, 2010 - March 26, 2013
For more information, please visit http://validform.rjboy.cn
Validform is available under the terms of the MIT license.
	
Demo:
$(".demoform").Validform({//$(".demoform")指明是哪一表单需要验证,名称需加在form表单上;
btnSubmit:"#btn_sub", //#btn_sub是该表单下要绑定点击提交表单事件的按钮;如果form内含有submit按钮该参数可省略;
btnReset:".btn_reset",//可选项 .btn_reset是该表单下要绑定点击重置表单事件的按钮;
tiptype:1, //可选项 1=>pop box,2=>side tip(parent.next.find; with default pop),3=>side tip(siblings; with default pop),4=>side tip(siblings; none pop)，默认为1，也可以传入一个function函数，自定义提示信息的显示方式（可以实现你想要的任何效果，具体参见demo页）;
ignoreHidden:false,//可选项 true | false 默认为false，当为true时对:hidden的表单元素将不做验证;
dragonfly:false,//可选项 true | false 默认false，当为true时，值为空时不做验证；
tipSweep:true,//可选项 true | false 默认为false，只在表单提交时触发检测，blur事件将不会触发检测（实时验证会在后台进行，不会显示检测结果）;
label:".label",//可选项 选择符，在没有绑定nullmsg时查找要显示的提示文字，默认查找".Validform_label"下的文字;
showAllError:false,//可选项 true | false，true：提交表单时所有错误提示信息都会显示，false：一碰到验证不通过的就停止检测后面的元素，只显示该元素的错误信息;
postonce:true, //可选项 表单是否只能提交一次，true开启，不填则默认关闭;
ajaxPost:true, //使用ajax方式提交表单数据，默认false，提交地址就是action指定地址;
datatype:{//传入自定义datatype类型，可以是正则，也可以是函数（函数内会传入一个参数）;
"*6-20": /^[^\s]{6,20}$/,
"z2-4" : /^[\u4E00-\u9FA5\uf900-\ufa2d]{2,4}$/,
"username":function(gets,obj,curform,regxp){
//参数gets是获取到的表单元素值，obj为当前表单元素，curform为当前验证的表单，regxp为内置的一些正则表达式的引用;
var reg1=/^[\w\.]{4,16}$/,
reg2=/^[\u4E00-\u9FA5\uf900-\ufa2d]{2,8}$/;
				
if(reg1.test(gets)){return true;}
if(reg2.test(gets)){return true;}
return false;
				
//注意return可以返回true 或 false 或 字符串文字，true表示验证通过，返回字符串表示验证失败，字符串作为错误提示显示，返回false则用errmsg或默认的错误提示;
},
"phone":function(){
// 5.0 版本之后，要实现二选一的验证效果，datatype 的名称 不 需要以 "option_" 开头;	
}
},
usePlugin:{
swfupload:{},
datepicker:{},
passwordstrength:{},
jqtransform:{
selector:"select,input"
}
},
beforeCheck:function(curform){
//在表单提交执行验证之前执行的函数，curform参数是当前表单对象。
//这里明确return false的话将不会继续执行验证操作;	
},
beforeSubmit:function(curform){
//在验证成功后，表单提交前执行的函数，curform参数是当前表单对象。
//这里明确return false的话表单将不会提交;	
},
callback:function(data){
//返回数据data是json格式，{"info":"demo info","status":"y"}
//info: 输出提示信息;
//status: 返回提交数据的状态,是否提交成功。如可以用"y"表示提交成功，"n"表示提交失败，在ajax_post.php文件返回数据里自定字符，主要用在callback函数里根据该值执行相应的回调操作;
//你也可以在ajax_post.php文件返回更多信息在这里获取，进行相应操作；
//ajax遇到服务端错误时也会执行回调，这时的data是{ status:**, statusText:**, readyState:**, responseText:** }；
			
//这里执行回调操作;
//注意：如果不是ajax方式提交表单，传入callback，这时data参数是当前表单对象，回调函数会在表单验证全部通过后执行，然后判断是否提交表单，如果callback里明确return false，则表单不会提交，如果return true或没有return，则会提交表单。
}
});
	
Validform对象的方法和属性：
tipmsg：自定义提示信息，通过修改Validform对象的这个属性值来让同一个页面的不同表单使用不同的提示文字；
dataType：获取内置的一些正则；
eq(n)：获取Validform对象的第n个元素;
ajaxPost(flag,sync,url)：以ajax方式提交表单。flag为true时，跳过验证直接提交，sync为true时将以同步的方式进行ajax提交，传入了url地址时，表单会提交到这个地址；
abort()：终止ajax的提交；
submitForm(flag,url)：以参数里设置的方式提交表单，flag为true时，跳过验证直接提交，传入了url地址时，表单会提交到这个地址；
resetForm()：重置表单；
resetStatus()：重置表单的提交状态。传入了postonce参数的话，表单成功提交后状态会设置为"posted"，重置提交状态可以让表单继续可以提交；
getStatus()：获取表单的提交状态，normal：未提交，posting：正在提交，posted：已成功提交过；
setStatus(status)：设置表单的提交状态，可以设置normal，posting，posted三种状态，不传参则设置状态为posting，这个状态表单可以验证，但不能提交；
ignore(selector)：忽略对所选择对象的验证；
unignore(selector)：将ignore方法所忽略验证的对象重新获取验证效果；
addRule(rule)：可以通过Validform对象的这个方法来给表单元素绑定验证规则；
check(bool,selector):对指定对象进行验证(默认验证当前整个表单)，通过返回true，否则返回false（绑定实时验证的对象，格式符合要求时返回true，而不会等ajax的返回结果），bool为true时则只验证不显示提示信息；
config(setup):可以通过这个方法来修改初始化参数，指定表单的提交地址，给表单ajax和实时验证的ajax里设置参数；
*/

(function ($, win, undef) {
    var errorobj = null, //指示当前验证失败的表单元素;
		msgobj = null, //pop box object 
		msghidden = true; //msgbox hidden?

    var tipmsg = {//默认提示文字;
        tit: "提示信息",
        w: {
            "*": "不能为空！",
            "*6-16": "请填写6到16位任意字符！",
            "n": "请填写数字！",
            "n6-16": "请填写6到16位数字！",
            "s": "不能输入特殊字符！",
            "s6-18": "请填写6到18位字符！",
            "p": "请填写邮政编码！",
            "m": "请填写手机号码！",
            "e": "邮箱地址格式不对！",
            "url": "请填写网址！"
        },
        def: "请填写正确信息！",
        undef: "datatype未定义！",
        reck: "两次输入的内容不一致！",
        r: "通过信息验证！",
        c: "正在检测信息…",
        s: "请{填写|选择}{0|信息}！",
        v: "所填信息没有经过验证，请稍后…",
        p: "正在提交数据…"
    }
    $.Tipmsg = tipmsg;

    var Validform = function (forms, settings, inited) {
        var settings = $.extend({}, Validform.defaults, settings);
        settings.datatype && $.extend(Validform.util.dataType, settings.datatype);

        var brothers = this;
        brothers.tipmsg = { w: {} };
        brothers.forms = forms;
        brothers.objects = [];

        //创建子对象时不再绑定事件;
        if (inited === true) {
            return false;
        }

        forms.each(function () {
            //已经绑定事件时跳过，避免事件重复绑定;
            if (this.validform_inited == "inited") { return true; }
            this.validform_inited = "inited";

            var curform = this;
            curform.settings = $.extend({}, settings);

            var $this = $(curform);

            //防止表单按钮双击提交两次;
            curform.validform_status = "normal"; //normal | posting | posted;

            //让每个Validform对象都能自定义tipmsg;	
            $this.data("tipmsg", brothers.tipmsg);

            //bind the blur event;
            $this.delegate("[datatype]", "blur", function () {
                //判断是否是在提交表单操作时触发的验证请求；
                var subpost = arguments[1];
                Validform.util.check.call(this, $this, subpost);
            });

            $this.delegate(":text", "keypress", function (event) {
                if (event.keyCode == 13 && $this.find(":submit").length == 0) {
                    $this.submit();
                }
            });

            //点击表单元素，默认文字消失效果;
            //表单元素值比较时的信息提示增强;
            //radio、checkbox提示信息增强;
            //外调插件初始化;
            Validform.util.enhance.call($this, curform.settings.tiptype, curform.settings.usePlugin, curform.settings.tipSweep);

            curform.settings.btnSubmit && $this.find(curform.settings.btnSubmit).bind("click", function () {
                $this.trigger("submit");
                return false;
            });

            $this.submit(function () {
                var subflag = Validform.util.submitForm.call($this, curform.settings);
                subflag === undef && (subflag = true);
                return subflag;
            });

            $this.find("[type='reset']").add($this.find(curform.settings.btnReset)).bind("click", function () {
                Validform.util.resetForm.call($this);
            });

        });

        //预创建pop box;
        if (settings.tiptype == 1 || (settings.tiptype == 2 || settings.tiptype == 3) && settings.ajaxPost) {
            creatMsgbox();
        }
    }

    Validform.defaults = {
        tiptype: 1,
        tipSweep: false,
        showAllError: false,
        postonce: false,
        ajaxPost: false
    }

    Validform.util = {
        dataType: {
            "*": /[\w\W]+/,
            "*6-16": /^[\w\W]{6,16}$/,
            "n": /^\d+$/,
            "n6-16": /^\d{6,16}$/,
            "s": /^[\u4E00-\u9FA5\uf900-\ufa2d\w\.\s]+$/,
            "s6-18": /^[\u4E00-\u9FA5\uf900-\ufa2d\w\.\s]{6,18}$/,
            "p": /^[0-9]{6}$/,
            "m": /^13[0-9]{9}$|14[0-9]{9}|15[0-9]{9}$|18[0-9]{9}$/,
            "e": /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
            "url": /^(\w+:\/\/)?\w+(\.\w+)+.*$/
        },

        toString: Object.prototype.toString,

        isEmpty: function (val) {
            return val === "" || val === $.trim(this.attr("tip"));
        },

        getValue: function (obj) {
            var inputval,
				curform = this;

            if (obj.is(":radio")) {
                inputval = curform.find(":radio[name='" + obj.attr("name") + "']:checked").val();
                inputval = inputval === undef ? "" : inputval;
            } else if (obj.is(":checkbox")) {
                inputval = "";
                curform.find(":checkbox[name='" + obj.attr("name") + "']:checked").each(function () {
                    inputval += $(this).val() + ',';
                })
                inputval = inputval === undef ? "" : inputval;
            } else {
                inputval = obj.val();
            }
            inputval = $.trim(inputval);

            return Validform.util.isEmpty.call(obj, inputval) ? "" : inputval;
        },

        enhance: function (tiptype, usePlugin, tipSweep, addRule) {
            var curform = this;

            //页面上不存在提示信息的标签时，自动创建;
            curform.find("[datatype]").each(function () {
                if (tiptype == 2) {
                    if ($(this).parent().next().find(".Validform_checktip").length == 0) {
                        $(this).parent().next().append("<span class='Validform_checktip' />");
                        $(this).siblings(".Validform_checktip").remove();
                    }
                } else if (tiptype == 3 || tiptype == 4) {
                    if ($(this).siblings(".Validform_checktip").length == 0) {
                        $(this).parent().append("<span class='Validform_checktip' />");
                        $(this).parent().next().find(".Validform_checktip").remove();
                    }
                }
            })

            //表单元素值比较时的信息提示增强;
            curform.find("input[recheck]").each(function () {
                //已经绑定事件时跳过;
                if (this.validform_inited == "inited") { return true; }
                this.validform_inited = "inited";

                var _this = $(this);
                var recheckinput = curform.find("input[name='" + $(this).attr("recheck") + "']");
                recheckinput.bind("keyup", function () {
                    if (recheckinput.val() == _this.val() && recheckinput.val() != "") {
                        if (recheckinput.attr("tip")) {
                            if (recheckinput.attr("tip") == recheckinput.val()) { return false; }
                        }
                        _this.trigger("blur");
                    }
                }).bind("blur", function () {
                    if (recheckinput.val() != _this.val() && _this.val() != "") {
                        if (_this.attr("tip")) {
                            if (_this.attr("tip") == _this.val()) { return false; }
                        }
                        _this.trigger("blur");
                    }
                });
            });

            //hasDefaultText;
            curform.find("[tip]").each(function () {//tip是表单元素的默认提示信息,这是点击清空效果;
                //已经绑定事件时跳过;
                if (this.validform_inited == "inited") { return true; }
                this.validform_inited = "inited";

                var defaultvalue = $(this).attr("tip");
                var altercss = $(this).attr("altercss");
                $(this).focus(function () {
                    if ($(this).val() == defaultvalue) {
                        $(this).val('');
                        if (altercss) { $(this).removeClass(altercss); }
                    }
                }).blur(function () {
                    if ($.trim($(this).val()) === '') {
                        $(this).val(defaultvalue);
                        if (altercss) { $(this).addClass(altercss); }
                    }
                });
            });

            //enhance info feedback for checkbox & radio;
            curform.find(":checkbox[datatype],:radio[datatype]").each(function () {
                //已经绑定事件时跳过;
                if (this.validform_inited == "inited") { return true; }
                this.validform_inited = "inited";

                var _this = $(this);
                var name = _this.attr("name");
                curform.find("[name='" + name + "']").filter(":checkbox,:radio").bind("click", function () {
                    //避免多个事件绑定时的取值滞后问题;
                    setTimeout(function () {
                        _this.trigger("blur");
                    }, 0);
                });

            });

            //select multiple;
            curform.find("select[datatype][multiple]").bind("click", function () {
                var _this = $(this);
                setTimeout(function () {
                    _this.trigger("blur");
                }, 0);
            });

            //plugins here to start;
            Validform.util.usePlugin.call(curform, usePlugin, tiptype, tipSweep, addRule);
        },

        usePlugin: function (plugin, tiptype, tipSweep, addRule) {
            /*
            plugin:settings.usePlugin;
            tiptype:settings.tiptype;
            tipSweep:settings.tipSweep;
            addRule:是否在addRule时触发;
            */

            var curform = this,
				plugin = plugin || {};
            //swfupload;
            if (curform.find("input[plugin='swfupload']").length && typeof (swfuploadhandler) != "undefined") {

                var custom = {
                    custom_settings: {
                        form: curform,
                        showmsg: function (msg, type, obj) {
                            Validform.util.showmsg.call(curform, msg, tiptype, { obj: curform.find("input[plugin='swfupload']"), type: type, sweep: tipSweep });
                        }
                    }
                };

                custom = $.extend(true, {}, plugin.swfupload, custom);

                curform.find("input[plugin='swfupload']").each(function (n) {
                    if (this.validform_inited == "inited") { return true; }
                    this.validform_inited = "inited";

                    $(this).val("");
                    swfuploadhandler.init(custom, n);
                });

            }

            //datepicker;
            if (curform.find("input[plugin='datepicker']").length && $.fn.datePicker) {
                plugin.datepicker = plugin.datepicker || {};

                if (plugin.datepicker.format) {
                    Date.format = plugin.datepicker.format;
                    delete plugin.datepicker.format;
                }
                if (plugin.datepicker.firstDayOfWeek) {
                    Date.firstDayOfWeek = plugin.datepicker.firstDayOfWeek;
                    delete plugin.datepicker.firstDayOfWeek;
                }

                curform.find("input[plugin='datepicker']").each(function (n) {
                    if (this.validform_inited == "inited") { return true; }
                    this.validform_inited = "inited";

                    plugin.datepicker.callback && $(this).bind("dateSelected", function () {
                        var d = new Date($.event._dpCache[this._dpId].getSelected()[0]).asString(Date.format);
                        plugin.datepicker.callback(d, this);
                    });
                    $(this).datePicker(plugin.datepicker);
                });
            }

            //passwordstrength;
            if (curform.find("input[plugin*='passwordStrength']").length && $.fn.passwordStrength) {
                plugin.passwordstrength = plugin.passwordstrength || {};
                plugin.passwordstrength.showmsg = function (obj, msg, type) {
                    Validform.util.showmsg.call(curform, msg, tiptype, { obj: obj, type: type, sweep: tipSweep });
                };

                curform.find("input[plugin='passwordStrength']").each(function (n) {
                    if (this.validform_inited == "inited") { return true; }
                    this.validform_inited = "inited";

                    $(this).passwordStrength(plugin.passwordstrength);
                });
            }

            //jqtransform;
            if (addRule != "addRule" && plugin.jqtransform && $.fn.jqTransSelect) {
                if (curform[0].jqTransSelected == "true") { return; };
                curform[0].jqTransSelected = "true";

                var jqTransformHideSelect = function (oTarget) {
                    var ulVisible = $('.jqTransformSelectWrapper ul:visible');
                    ulVisible.each(function () {
                        var oSelect = $(this).parents(".jqTransformSelectWrapper:first").find("select").get(0);
                        //do not hide if click on the label object associated to the select
                        if (!(oTarget && oSelect.oLabel && oSelect.oLabel.get(0) == oTarget.get(0))) { $(this).hide(); }
                    });
                };

                /* Check for an external click */
                var jqTransformCheckExternalClick = function (event) {
                    if ($(event.target).parents('.jqTransformSelectWrapper').length === 0) { jqTransformHideSelect($(event.target)); }
                };

                var jqTransformAddDocumentListener = function () {
                    $(document).mousedown(jqTransformCheckExternalClick);
                };

                if (plugin.jqtransform.selector) {
                    curform.find(plugin.jqtransform.selector).filter('input:submit, input:reset, input[type="button"]').jqTransInputButton();
                    curform.find(plugin.jqtransform.selector).filter('input:text, input:password').jqTransInputText();
                    curform.find(plugin.jqtransform.selector).filter('input:checkbox').jqTransCheckBox();
                    curform.find(plugin.jqtransform.selector).filter('input:radio').jqTransRadio();
                    curform.find(plugin.jqtransform.selector).filter('textarea').jqTransTextarea();
                    if (curform.find(plugin.jqtransform.selector).filter("select").length > 0) {
                        curform.find(plugin.jqtransform.selector).filter("select").jqTransSelect();
                        jqTransformAddDocumentListener();
                    }

                } else {
                    curform.jqTransform();
                }

                curform.find(".jqTransformSelectWrapper").find("li a").click(function () {
                    $(this).parents(".jqTransformSelectWrapper").find("select").trigger("blur");
                });
            }

        },

        getNullmsg: function (curform) {
            var obj = this;
            var reg = /[\u4E00-\u9FA5\uf900-\ufa2da-zA-Z\s]+/g;
            var nullmsg;

            var label = curform[0].settings.label || ".Validform_label";
            label = obj.siblings(label).eq(0).text() || obj.siblings().find(label).eq(0).text() || obj.parent().siblings(label).eq(0).text() || obj.parent().siblings().find(label).eq(0).text();
            label = label.replace(/\s(?![a-zA-Z])/g, "").match(reg);
            label = label ? label.join("") : [""];

            reg = /\{(.+)\|(.+)\}/;
            nullmsg = curform.data("tipmsg").s || tipmsg.s;

            if (label != "") {
                nullmsg = nullmsg.replace(/\{0\|(.+)\}/, label);
                if (obj.attr("recheck")) {
                    nullmsg = nullmsg.replace(/\{(.+)\}/, "");
                    obj.attr("nullmsg", nullmsg);
                    return nullmsg;
                }
            } else {
                nullmsg = obj.is(":checkbox,:radio,select") ? nullmsg.replace(/\{0\|(.+)\}/, "") : nullmsg.replace(/\{0\|(.+)\}/, "$1");
            }
            nullmsg = obj.is(":checkbox,:radio,select") ? nullmsg.replace(reg, "$2") : nullmsg.replace(reg, "$1");

            obj.attr("nullmsg", nullmsg);
            return nullmsg;
        },

        getErrormsg: function (curform, datatype, recheck) {
            var regxp = /^(.+?)((\d+)-(\d+))?$/,
				regxp2 = /^(.+?)(\d+)-(\d+)$/,
				regxp3 = /(.*?)\d+(.+?)\d+(.*)/,
				mac = datatype.match(regxp),
				temp, str;

            //如果是值不一样而报错;
            if (recheck == "recheck") {
                str = curform.data("tipmsg").reck || tipmsg.reck;
                return str;
            }

            var tipmsg_w_ex = $.extend({}, tipmsg.w, curform.data("tipmsg").w);

            //如果原来就有，直接显示该项的提示信息;
            if (mac[0] in tipmsg_w_ex) {
                return curform.data("tipmsg").w[mac[0]] || tipmsg.w[mac[0]];
            }

            //没有的话在提示对象里查找相似;
            for (var name in tipmsg_w_ex) {
                if (name.indexOf(mac[1]) != -1 && regxp2.test(name)) {
                    str = (curform.data("tipmsg").w[name] || tipmsg.w[name]).replace(regxp3, "$1" + mac[3] + "$2" + mac[4] + "$3");
                    curform.data("tipmsg").w[mac[0]] = str;

                    return str;
                }

            }

            return curform.data("tipmsg").def || tipmsg.def;
        },

        _regcheck: function (datatype, gets, obj, curform) {
            var curform = curform,
				info = null,
				passed = false,
				reg = /\/.+\//g,
				regex = /^(.+?)(\d+)-(\d+)$/,
				type = 3; //default set to wrong type, 2,3,4;

            //datatype有三种情况：正则，函数和直接绑定的正则;

            //直接是正则;
            if (reg.test(datatype)) {
                var regstr = datatype.match(reg)[0].slice(1, -1);
                var param = datatype.replace(reg, "");
                var rexp = RegExp(regstr, param);

                passed = rexp.test(gets);

                //function;
            } else if (Validform.util.toString.call(Validform.util.dataType[datatype]) == "[object Function]") {
                passed = Validform.util.dataType[datatype](gets, obj, curform, Validform.util.dataType);
                if (passed === true || passed === undef) {
                    passed = true;
                } else {
                    info = passed;
                    passed = false;
                }

                //自定义正则;	
            } else {
                //自动扩展datatype;
                if (!(datatype in Validform.util.dataType)) {
                    var mac = datatype.match(regex),
						temp;

                    if (!mac) {
                        passed = false;
                        info = curform.data("tipmsg").undef || tipmsg.undef;
                    } else {
                        for (var name in Validform.util.dataType) {
                            temp = name.match(regex);
                            if (!temp) { continue; }
                            if (mac[1] === temp[1]) {
                                var str = Validform.util.dataType[name].toString(),
									param = str.match(/\/[mgi]*/g)[1].replace("\/", ""),
									regxp = new RegExp("\\{" + temp[2] + "," + temp[3] + "\\}", "g");
                                str = str.replace(/\/[mgi]*/g, "\/").replace(regxp, "{" + mac[2] + "," + mac[3] + "}").replace(/^\//, "").replace(/\/$/, "");
                                Validform.util.dataType[datatype] = new RegExp(str, param);
                                break;
                            }
                        }
                    }
                }

                if (Validform.util.toString.call(Validform.util.dataType[datatype]) == "[object RegExp]") {
                    passed = Validform.util.dataType[datatype].test(gets);
                }

            }


            if (passed) {
                type = 2;
                info = obj.attr("sucmsg") || curform.data("tipmsg").r || tipmsg.r;

                //规则验证通过后，还需要对绑定recheck的对象进行值比较;
                if (obj.attr("recheck")) {
                    var theother = curform.find("input[name='" + obj.attr("recheck") + "']:first");
                    if (gets != theother.val()) {
                        passed = false;
                        type = 3;
                        info = obj.attr("errormsg") || Validform.util.getErrormsg.call(obj, curform, datatype, "recheck");
                    }
                }
            } else {
                info = info || obj.attr("errormsg") || Validform.util.getErrormsg.call(obj, curform, datatype);

                //验证不通过且为空时;
                if (Validform.util.isEmpty.call(obj, gets)) {
                    info = obj.attr("nullmsg") || Validform.util.getNullmsg.call(obj, curform);
                }
            }

            return {
                passed: passed,
                type: type,
                info: info
            };

        },

        regcheck: function (datatype, gets, obj) {
            /*
            datatype:datatype;
            gets:inputvalue;
            obj:input object;
            */
            var curform = this,
				info = null,
				passed = false,
				type = 3; //default set to wrong type, 2,3,4;

            //ignore;
            if (obj.attr("ignore") === "ignore" && Validform.util.isEmpty.call(obj, gets)) {
                if (obj.data("cked")) {
                    info = "";
                }

                return {
                    passed: true,
                    type: 4,
                    info: info
                };
            }

            obj.data("cked", "cked"); //do nothing if is the first time validation triggered;

            var dtype = Validform.util.parseDatatype(datatype);
            var res;
            for (var eithor = 0; eithor < dtype.length; eithor++) {
                for (var dtp = 0; dtp < dtype[eithor].length; dtp++) {
                    res = Validform.util._regcheck(dtype[eithor][dtp], gets, obj, curform);
                    if (!res.passed) {
                        break;
                    }
                }
                if (res.passed) {
                    break;
                }
            }
            return res;

        },

        parseDatatype: function (datatype) {
            /*
            字符串里面只能含有一个正则表达式;
            Datatype名称必须是字母，数字、下划线或*号组成;
            datatype="/regexp/|phone|tel,s,e|f,e";
            ==>[["/regexp/"],["phone"],["tel","s","e"],["f","e"]];
            */

            var reg = /\/.+?\/[mgi]*(?=(,|$|\||\s))|[\w\*-]+/g,
				dtype = datatype.match(reg),
				sepor = datatype.replace(reg, "").replace(/\s*/g, "").split(""),
				arr = [],
				m = 0;

            arr[0] = [];
            arr[0].push(dtype[0]);
            for (var n = 0; n < sepor.length; n++) {
                if (sepor[n] == "|") {
                    m++;
                    arr[m] = [];
                }
                arr[m].push(dtype[n + 1]);
            }

            return arr;
        },

        showmsg: function (msg, type, o, triggered) {
            /*
            msg:提示文字;
            type:提示信息显示方式;
            o:{obj:当前对象, type:1=>正在检测 | 2=>通过, sweep:true | false}, 
            triggered:在blur或提交表单触发的验证中，有些情况不需要显示提示文字，如自定义弹出提示框的显示方式，不需要每次blur时就马上弹出提示;
				
            tiptype:1\2\3时都有坑能会弹出自定义提示框
            tiptype:1时在triggered bycheck时不弹框
            tiptype:2\3时在ajax时弹框
            tipSweep为true时在triggered bycheck时不触发showmsg，但ajax出错的情况下要提示
            */

            //如果msg为undefined，那么就没必要执行后面的操作，ignore有可能会出现这情况;
            if (msg == undef) { return; }

            //tipSweep为true，且当前不是处于错误状态时，blur事件不触发信息显示;
            if (triggered == "bycheck" && o.sweep && (o.obj && !o.obj.is(".Validform_error") || typeof type == "function")) { return; }

            $.extend(o, { curform: this });

            if (typeof type == "function") {
                type(msg, o, Validform.util.cssctl);
                return;
            }

            if (type == 1 || triggered == "byajax" && type != 4) {
                msgobj.find(".Validform_info").html(msg);
            }

            //tiptypt=1时，blur触发showmsg，验证是否通过都不弹框，提交表单触发的话，只要验证出错，就弹框;
            if (type == 1 && triggered != "bycheck" && o.type != 2 || triggered == "byajax" && type != 4) {
                msghidden = false;
                msgobj.find(".iframe").css("height", msgobj.outerHeight());
                msgobj.show();
                setCenter(msgobj, 100);
            }

            if (type == 2 && o.obj) {
                o.obj.parent().next().find(".Validform_checktip").html(msg);
                Validform.util.cssctl(o.obj.parent().next().find(".Validform_checktip"), o.type);
            }

            if ((type == 3 || type == 4) && o.obj) {
                o.obj.siblings(".Validform_checktip").html(msg);
                Validform.util.cssctl(o.obj.siblings(".Validform_checktip"), o.type);
            }

        },

        cssctl: function (obj, status) {
            switch (status) {
                case 1:
                    obj.removeClass("Validform_right Validform_wrong").addClass("Validform_checktip Validform_loading"); //checking;
                    break;
                case 2:
                    obj.removeClass("Validform_wrong Validform_loading").addClass("Validform_checktip Validform_right"); //passed;
                    break;
                case 4:
                    obj.removeClass("Validform_right Validform_wrong Validform_loading").addClass("Validform_checktip"); //for ignore;
                    break;
                default:
                    obj.removeClass("Validform_right Validform_loading").addClass("Validform_checktip Validform_wrong"); //wrong;
            }
        },

        check: function (curform, subpost, bool) {
            /*
            检测单个表单元素;
            验证通过返回true，否则返回false、实时验证返回值为ajax;
            bool，传入true则只检测不显示提示信息;
            */
            var settings = curform[0].settings;
            var subpost = subpost || "";
            var inputval = Validform.util.getValue.call(curform, $(this));

            //隐藏或绑定dataIgnore的表单对象不做验证;
            if (settings.ignoreHidden && $(this).is(":hidden") || $(this).data("dataIgnore") === "dataIgnore") {
                return true;
            }

            //dragonfly=true时，没有绑定ignore，值为空不做验证，但验证不通过;
            if (settings.dragonfly && !$(this).data("cked") && Validform.util.isEmpty.call($(this), inputval) && $(this).attr("ignore") != "ignore") {
                return false;
            }

            var flag = Validform.util.regcheck.call(curform, $(this).attr("datatype"), inputval, $(this));

            //值没变化不做检测，这时要考虑recheck情况;
            //不是在提交表单时触发的ajax验证;
            if (inputval == this.validform_lastval && !$(this).attr("recheck") && subpost == "") {
                return flag.passed ? true : false;
            }

            this.validform_lastval = inputval; //存储当前值;

            var _this;
            errorobj = _this = $(this);

            if (!flag.passed) {
                //取消正在进行的ajax验证;
                Validform.util.abort.call(_this[0]);

                if (!bool) {
                    //传入"bycheck"，指示当前是check方法里调用的，当tiptype=1时，blur事件不让触发错误信息显示;
                    Validform.util.showmsg.call(curform, flag.info, settings.tiptype, { obj: $(this), type: flag.type, sweep: settings.tipSweep }, "bycheck");

                    !settings.tipSweep && _this.addClass("Validform_error");
                }
                return false;
            }

            //验证通过的话，如果绑定有ajaxurl，要执行ajax检测;
            //当ignore="ignore"时，为空值可以通过验证，这时不需要ajax检测;
            var ajaxurl = $(this).attr("ajaxurl");
            if (ajaxurl && !Validform.util.isEmpty.call($(this), inputval) && !bool) {
                var inputobj = $(this);

                //当提交表单时，表单中的某项已经在执行ajax检测，这时需要让该项ajax结束后继续提交表单;
                if (subpost == "postform") {
                    inputobj[0].validform_subpost = "postform";
                } else {
                    inputobj[0].validform_subpost = "";
                }

                if (inputobj[0].validform_valid === "posting" && inputval == inputobj[0].validform_ckvalue) { return "ajax"; }

                inputobj[0].validform_valid = "posting";
                inputobj[0].validform_ckvalue = inputval;
                Validform.util.showmsg.call(curform, curform.data("tipmsg").c || tipmsg.c, settings.tiptype, { obj: inputobj, type: 1, sweep: settings.tipSweep }, "bycheck");

                Validform.util.abort.call(_this[0]);

                var ajaxsetup = $.extend(true, {}, settings.ajaxurl || {});

                var localconfig = {
                    type: "POST",
                    cache: false,
                    url: ajaxurl,
                    data: "param=" + encodeURIComponent(inputval) + "&name=" + encodeURIComponent($(this).attr("name")),
                    success: function (data) {
                        if ($.trim(data.status) === "y") {
                            inputobj[0].validform_valid = "true";
                            data.info && inputobj.attr("sucmsg", data.info);
                            Validform.util.showmsg.call(curform, inputobj.attr("sucmsg") || curform.data("tipmsg").r || tipmsg.r, settings.tiptype, { obj: inputobj, type: 2, sweep: settings.tipSweep }, "bycheck");
                            _this.removeClass("Validform_error");
                            errorobj = null;
                            if (inputobj[0].validform_subpost == "postform") {
                                curform.trigger("submit");
                            }
                        } else {
                            inputobj[0].validform_valid = data.info;
                            Validform.util.showmsg.call(curform, data.info, settings.tiptype, { obj: inputobj, type: 3, sweep: settings.tipSweep });
                            _this.addClass("Validform_error");
                        }
                        _this[0].validform_ajax = null;
                    },
                    error: function (data) {
                        if (data.status == "200") {
                            if (data.responseText == "y") {
                                ajaxsetup.success({ "status": "y" });
                            } else {
                                ajaxsetup.success({ "status": "n", "info": data.responseText });
                            }
                            return false;
                        }

                        //正在检测时，要检测的数据发生改变，这时要终止当前的ajax。不是这种情况引起的ajax错误，那么显示相关错误信息;
                        if (data.statusText !== "abort") {
                            var msg = "status: " + data.status + "; statusText: " + data.statusText;

                            Validform.util.showmsg.call(curform, msg, settings.tiptype, { obj: inputobj, type: 3, sweep: settings.tipSweep });
                            _this.addClass("Validform_error");
                        }

                        inputobj[0].validform_valid = data.statusText;
                        _this[0].validform_ajax = null;

                        //localconfig.error返回true表示还需要执行temp_err;
                        return true;
                    }
                }

                if (ajaxsetup.success) {
                    var temp_suc = ajaxsetup.success;
                    ajaxsetup.success = function (data) {
                        localconfig.success(data);
                        temp_suc(data, inputobj);
                    }
                }

                if (ajaxsetup.error) {
                    var temp_err = ajaxsetup.error;
                    ajaxsetup.error = function (data) {
                        //localconfig.error返回false表示不需要执行temp_err;
                        localconfig.error(data) && temp_err(data, inputobj);
                    }
                }

                ajaxsetup = $.extend({}, localconfig, ajaxsetup, { dataType: "json" });
                _this[0].validform_ajax = $.ajax(ajaxsetup);

                return "ajax";
            } else if (ajaxurl && Validform.util.isEmpty.call($(this), inputval)) {
                Validform.util.abort.call(_this[0]);
                _this[0].validform_valid = "true";
            }

            if (!bool) {
                Validform.util.showmsg.call(curform, flag.info, settings.tiptype, { obj: $(this), type: flag.type, sweep: settings.tipSweep }, "bycheck");
                _this.removeClass("Validform_error");
            }
            errorobj = null;

            return true;

        },

        submitForm: function (settings, flg, url, ajaxPost, sync) {
            /*
            flg===true时跳过验证直接提交;
            ajaxPost==="ajaxPost"指示当前表单以ajax方式提交;
            */
            var curform = this;

            //表单正在提交时点击提交按钮不做反应;
            if (curform[0].validform_status === "posting") { return false; }

            //要求只能提交一次时;
            if (settings.postonce && curform[0].validform_status === "posted") { return false; }

            var beforeCheck = settings.beforeCheck && settings.beforeCheck(curform);
            if (beforeCheck === false) { return false; }

            var flag = true,
				inflag;

            curform.find("[datatype]").each(function () {
                //跳过验证;
                if (flg) {
                    return false;
                }

                //隐藏或绑定dataIgnore的表单对象不做验证;
                if (settings.ignoreHidden && $(this).is(":hidden") || $(this).data("dataIgnore") === "dataIgnore") {
                    return true;
                }

                var inputval = Validform.util.getValue.call(curform, $(this)),
					_this;
                errorobj = _this = $(this);

                inflag = Validform.util.regcheck.call(curform, $(this).attr("datatype"), inputval, $(this));

                if (!inflag.passed) {
                    Validform.util.showmsg.call(curform, inflag.info, settings.tiptype, { obj: $(this), type: inflag.type, sweep: settings.tipSweep });
                    _this.addClass("Validform_error");

                    if (!settings.showAllError) {
                        _this.focus();
                        flag = false;
                        return false;
                    }

                    flag && (flag = false);
                    return true;
                }

                //当ignore="ignore"时，为空值可以通过验证，这时不需要ajax检测;
                if ($(this).attr("ajaxurl") && !Validform.util.isEmpty.call($(this), inputval)) {
                    if (this.validform_valid !== "true") {
                        var thisobj = $(this);
                        Validform.util.showmsg.call(curform, curform.data("tipmsg").v || tipmsg.v, settings.tiptype, { obj: thisobj, type: 3, sweep: settings.tipSweep });
                        _this.addClass("Validform_error");

                        thisobj.trigger("blur", ["postform"]); //continue the form post;

                        if (!settings.showAllError) {
                            flag = false;
                            return false;
                        }

                        flag && (flag = false);
                        return true;
                    }
                } else if ($(this).attr("ajaxurl") && Validform.util.isEmpty.call($(this), inputval)) {
                    Validform.util.abort.call(this);
                    this.validform_valid = "true";
                }

                Validform.util.showmsg.call(curform, inflag.info, settings.tiptype, { obj: $(this), type: inflag.type, sweep: settings.tipSweep });
                _this.removeClass("Validform_error");
                errorobj = null;
            });

            if (settings.showAllError) {
                curform.find(".Validform_error:first").focus();
            }

            if (flag) {
                var beforeSubmit = settings.beforeSubmit && settings.beforeSubmit(curform);
                if (beforeSubmit === false) { return false; }

                curform[0].validform_status = "posting";

                if (settings.ajaxPost || ajaxPost === "ajaxPost") {
                    //获取配置参数;
                    var ajaxsetup = $.extend(true, {}, settings.ajaxpost || {});
                    //有可能需要动态的改变提交地址，所以把action所指定的url层级设为最低;
                    ajaxsetup.url = url || ajaxsetup.url || settings.url || curform.attr("action");

                    //byajax：ajax时，tiptye为1、2或3需要弹出提示框;
                    Validform.util.showmsg.call(curform, curform.data("tipmsg").p || tipmsg.p, settings.tiptype, { obj: curform, type: 1, sweep: settings.tipSweep }, "byajax");

                    //方法里的优先级要高;
                    //有undefined情况;
                    if (sync) {
                        ajaxsetup.async = false;
                    } else if (sync === false) {
                        ajaxsetup.async = true;
                    }

                    if (ajaxsetup.success) {
                        var temp_suc = ajaxsetup.success;
                        ajaxsetup.success = function (data) {
                            settings.callback && settings.callback(data);
                            curform[0].validform_ajax = null;
                            if ($.trim(data.status) === "y") {
                                curform[0].validform_status = "posted";
                            } else {
                                curform[0].validform_status = "normal";
                            }

                            temp_suc(data, curform);
                        }
                    }

                    if (ajaxsetup.error) {
                        var temp_err = ajaxsetup.error;
                        ajaxsetup.error = function (data) {
                            settings.callback && settings.callback(data);
                            curform[0].validform_status = "normal";
                            curform[0].validform_ajax = null;

                            temp_err(data, curform);
                        }
                    }

                    var localconfig = {
                        type: "POST",
                        async: true,
                        data: curform.serializeArray(),
                        success: function (data) {
                            if ($.trim(data.status) === "y") {
                                //成功提交;
                                curform[0].validform_status = "posted";
                                Validform.util.showmsg.call(curform, data.info, settings.tiptype, { obj: curform, type: 2, sweep: settings.tipSweep }, "byajax");
                            } else {
                                //提交出错;
                                curform[0].validform_status = "normal";
                                Validform.util.showmsg.call(curform, data.info, settings.tiptype, { obj: curform, type: 3, sweep: settings.tipSweep }, "byajax");
                            }

                            settings.callback && settings.callback(data);
                            curform[0].validform_ajax = null;
                        },
                        error: function (data) {
                            var msg = "status: " + data.status + "; statusText: " + data.statusText;

                            Validform.util.showmsg.call(curform, msg, settings.tiptype, { obj: curform, type: 3, sweep: settings.tipSweep }, "byajax");

                            settings.callback && settings.callback(data);
                            curform[0].validform_status = "normal";
                            curform[0].validform_ajax = null;
                        }
                    }

                    ajaxsetup = $.extend({}, localconfig, ajaxsetup, { dataType: "json" });

                    curform[0].validform_ajax = $.ajax(ajaxsetup);

                } else {
                    if (!settings.postonce) {
                        curform[0].validform_status = "normal";
                    }

                    var url = url || settings.url;
                    if (url) {
                        curform.attr("action", url);
                    }

                    return settings.callback && settings.callback(curform);
                }
            }

            return false;

        },

        resetForm: function () {
            var brothers = this;
            brothers.each(function () {
                this.reset && this.reset();
                this.validform_status = "normal";
            });

            brothers.find(".Validform_right").text("");
            brothers.find(".passwordStrength").children().removeClass("bgStrength");
            brothers.find(".Validform_checktip").removeClass("Validform_wrong Validform_right Validform_loading");
            brothers.find(".Validform_error").removeClass("Validform_error");
            brothers.find("[datatype]").removeData("cked").removeData("dataIgnore").each(function () {
                this.validform_lastval = null;
            });
            brothers.eq(0).find("input:first").focus();
        },

        abort: function () {
            if (this.validform_ajax) {
                this.validform_ajax.abort();
            }
        }

    }

    $.Datatype = Validform.util.dataType;

    Validform.prototype = {
        dataType: Validform.util.dataType,

        eq: function (n) {
            var obj = this;

            if (n >= obj.forms.length) {
                return null;
            }

            if (!(n in obj.objects)) {
                obj.objects[n] = new Validform($(obj.forms[n]).get(), {}, true);
            }

            return obj.objects[n];

        },

        resetStatus: function () {
            var obj = this;
            $(obj.forms).each(function () {
                this.validform_status = "normal";
            });

            return this;
        },

        setStatus: function (status) {
            var obj = this;
            $(obj.forms).each(function () {
                this.validform_status = status || "posting";
            });

            return this;
        },

        getStatus: function () {
            var obj = this;
            var status = $(obj.forms)[0].validform_status;

            return status;
        },

        ignore: function (selector) {
            var obj = this;
            var selector = selector || "[datatype]"

            $(obj.forms).find(selector).each(function () {
                $(this).data("dataIgnore", "dataIgnore").removeClass("Validform_error");
            });

            return this;
        },

        unignore: function (selector) {
            var obj = this;
            var selector = selector || "[datatype]"

            $(obj.forms).find(selector).each(function () {
                $(this).removeData("dataIgnore");
            });

            return this;
        },

        addRule: function (rule) {
            /*
            rule => [{
            ele:"#id",
            datatype:"*",
            errormsg:"出错提示文字！",
            nullmsg:"为空时的提示文字！",
            tip:"默认显示的提示文字",
            altercss:"gray",
            ignore:"ignore",
            ajaxurl:"valid.php",
            recheck:"password",
            plugin:"passwordStrength"
            },{},{},...]
            */
            var obj = this;
            var rule = rule || [];

            for (var index = 0; index < rule.length; index++) {
                var o = $(obj.forms).find(rule[index].ele);
                for (var attr in rule[index]) {
                    attr !== "ele" && o.attr(attr, rule[index][attr]);
                }
            }

            $(obj.forms).each(function () {
                var $this = $(this);
                Validform.util.enhance.call($this, this.settings.tiptype, this.settings.usePlugin, this.settings.tipSweep, "addRule");
            });

            return this;
        },

        ajaxPost: function (flag, sync, url) {
            var obj = this;

            $(obj.forms).each(function () {
                //创建pop box;
                if (this.settings.tiptype == 1 || this.settings.tiptype == 2 || this.settings.tiptype == 3) {
                    creatMsgbox();
                }

                Validform.util.submitForm.call($(obj.forms[0]), this.settings, flag, url, "ajaxPost", sync);
            });

            return this;
        },

        submitForm: function (flag, url) {
            /*flag===true时不做验证直接提交*/


            var obj = this;

            $(obj.forms).each(function () {
                var subflag = Validform.util.submitForm.call($(this), this.settings, flag, url);
                subflag === undef && (subflag = true);
                if (subflag === true) {
                    this.submit();
                }
            });

            return this;
        },

        resetForm: function () {
            var obj = this;
            Validform.util.resetForm.call($(obj.forms));

            return this;
        },

        abort: function () {
            var obj = this;
            $(obj.forms).each(function () {
                Validform.util.abort.call(this);
            });

            return this;
        },

        check: function (bool, selector) {
            /*
            bool：传入true，只检测不显示提示信息;
            */

            var selector = selector || "[datatype]",
				obj = this,
				curform = $(obj.forms),
				flag = true;

            curform.find(selector).each(function () {
                Validform.util.check.call(this, curform, "", bool) || (flag = false);
            });

            return flag;
        },

        config: function (setup) {
            /*
            config={
            url:"ajaxpost.php",//指定了url后，数据会提交到这个地址;
            ajaxurl:{
            timeout:1000,
            ...
            },
            ajaxpost:{
            timeout:1000,
            ...
            }
            }
            */
            var obj = this;
            setup = setup || {};
            $(obj.forms).each(function () {
                var $this = $(this);
                this.settings = $.extend(true, this.settings, setup);
                Validform.util.enhance.call($this, this.settings.tiptype, this.settings.usePlugin, this.settings.tipSweep);
            });

            return this;
        }
    }

    $.fn.Validform = function (settings) {
        return new Validform(this, settings);
    };

    function setCenter(obj, time) {
        var left = ($(window).width() - obj.outerWidth()) / 2,
			top = ($(window).height() - obj.outerHeight()) / 2,

		top = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + (top > 0 ? top : 0);

        obj.css({
            left: left
        }).animate({
            top: top
        }, { duration: time, queue: false });
    }

    function creatMsgbox() {
        if ($("#Validform_msg").length !== 0) { return false; }
        msgobj = $('<div id="Validform_msg"><div class="Validform_title">' + tipmsg.tit + '<a class="Validform_close" href="javascript:void(0);">&chi;</a></div><div class="Validform_info"></div><div class="iframe"><iframe frameborder="0" scrolling="no" height="100%" width="100%"></iframe></div></div>').appendTo("body"); //提示信息框;
        msgobj.find("a.Validform_close").click(function () {
            msgobj.hide();
            msghidden = true;
            if (errorobj) {
                errorobj.focus().addClass("Validform_error");
            }
            return false;
        }).focus(function () { this.blur(); });

        $(window).bind("scroll resize", function () {
            !msghidden && setCenter(msgobj, 400);
        });
    };

    //公用方法显示&关闭信息提示框;
    $.Showmsg = function (msg) {
        creatMsgbox();
        Validform.util.showmsg.call(win, msg, 1, {});
    };

    $.Hidemsg = function () {
        msgobj.hide();
        msghidden = true;
    };

})(jQuery, window);